package org.ly817.my.spring.core.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.ly817.my.spring.core.aop.pointcut.AspectJExpressionPointcutAdvisor;
import org.ly817.my.spring.core.ioc.bean.enhance.BeanFactoryAware;
import org.ly817.my.spring.core.ioc.bean.enhance.BeanPostProcessor;
import org.ly817.my.spring.core.ioc.factory.AbstractBeanFactory;
import org.ly817.my.spring.core.ioc.factory.BeanFactory;

import java.util.List;

/**
 * 切面逻辑织入器
 * 实现BeanPostProcessor接口
 * 在bean实例化时，对初始化的bean进行处理
 * <p>
 *
 * @author LuoYu
 * @date 2018/5/3
 */
public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {

    /**
     * 用户获取容器中的切面逻辑适配器
     *
     * @see AspectJExpressionPointcutAdvisor
     */
    private AbstractBeanFactory beanFactory;

    private List<AspectJExpressionPointcutAdvisor> aspectJExpressionAdvisors;

    private List<AspectJExpressionPointcutAdvisor> getAspectJExpressionPointcutAdvisors() throws Exception {
        if (aspectJExpressionAdvisors == null) {
            aspectJExpressionAdvisors = beanFactory.getBeansByType(AspectJExpressionPointcutAdvisor.class);
        }
        return this.aspectJExpressionAdvisors;
    }

    /**
     *
     */
    private boolean isTargetBean(Object bean) {
        boolean flag = true;
        if (bean instanceof AspectJExpressionPointcutAdvisor) {
            flag = false;
        }
        if (bean instanceof MethodInterceptor) {
            flag = false;
        }
        return flag;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = (AbstractBeanFactory) beanFactory;
    }

    /**
     * TODO
     * 调用任何bean的初始化钩子（例如InitializingBean.afterPropertiesSet或者init方法）之前被调用
     *
     * @param bean
     * @param beanName
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
        if (isTargetBean(bean)) {
            // 扫描aspectJExpressionAdvisors，得到匹配的切面适配器，对bean进行装饰，生成代理类
            for (AspectJExpressionPointcutAdvisor advisor : getAspectJExpressionPointcutAdvisors()) {
                if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) {
                    AdviceSupport advisedSupport = new AdviceSupport();
                    advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
                    advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
                    TargetSource targetSource = new TargetSource(bean, bean.getClass().getInterfaces());
                    advisedSupport.setTargetSource(targetSource);
                    Object result = new JdkDynamicAopProxy(advisedSupport).getProxy();
                    return result;
                }
            }
        }
        return bean;
    }

    /**
     * TODO 在成功完成嵌入初始化以后调用
     *
     * @param bean
     * @param beanName
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
        return bean;
    }


}
